home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-02
/
pas_all.zip
/
TI152.ASC
< prev
next >
Wrap
Text File
|
1992-09-02
|
22KB
|
661 lines
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 1/10
TITLE : INTERRUPT HANDLER
The following example routines are public domain programs that
have been uploaded to our Forum on CompuServe. As a courtesy to
our users that do not have immediate access to CompuServe,
Technical Support distributes these routines free of charge.
However, because these routines are public domain programs, not
developed by Borland International, we are unable to provide any
technical support or assistance using these routines. If you need
assistance using these routines, or are experiencing difficu
DumbTerm is an example program written to demonstrate the use of
both interrupt routines and COM port communication. There are
some inline instructions that are used in the interrupt routine
that do not appear in the Turbo Pascal manual. When making you
This program was written by:
Jim McCarthy and Andy Batony
Technical Support Teleware Incorporated
Borland International
_____________________________________________________________________
---------------------------------------------------------------------
PROGRAM dumbterm;
CONST
hex : string[16] = '0123456789ABCDEF'; { Constant used to }
{ convert decimal to hex }
irq4 = $30; { Interrupt vector address }
{ for COM1. }
irq3 = $2C; { Vector for COM2. }
eoi = $20; { }
com1base = $03F8; { Port address of COM1. }
com2base = $02F8; { Port address of COM2. }
{ Offset to add to }
intenreg = 1; { com#base for Interrupt }
{ enable register }
intidreg = 2; { Interrupt id register }
linectrl = 3; { Line control register }
modemctrl = 4; { Modem control register }
linestat = 5; { Line status register }
modemstat = 6; { Modem status register }
buffsize = 1024; { Size of the ring buffer }
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 2/10
TITLE : INTERRUPT HANDLER
TYPE { Type declarations }
str4 = string[4];
str80 = string[80];
ratetype = (rate300,rate1200,rate4800,rate9600);
comtype = (com1,com2);
bytechar = record case boolean of
true :(o:byte);
false:(c:char)
end;
regrec = record
ax,bx,cx,dx,bp,di,si,ds,es,flags : integer;
end;
VAR
segment : integer absolute cseg:$00A0; { Address for storing }
intbuffer : array [0..buffsize] of bytechar; { DS Ring buffer }
oldvecseg, { Segment of DOS set }
oldvecoff, { Offset of DOS set com int. }
head, { Index to the head of the }
{ ring buffer. }
tail, { Tail index of the ring buff }
comport, { Comport address }
i : integer; { Counter }
comp : comtype; { Used to specify which comport }
ch, { Temporary character buffer }
kch : char; { Char keyed in from the key- }
{ board }
temp : string[80]; { Temporary buffer }
tbyte,
lbyte : byte;
showok : boolean;
registers : regrec; { Registers used in DOS call }
{--------------------------------------------------------------------
This is the interrupt handler for the COM1 or COM2 comports. Notice the
restoration of the DS register through a move to the AX from address
CS:00A0. The absolute variable "segment" is initialized at the beginning
of the program to contain the value of "
--------------------------------------------------------------------}
PROCEDURE IntHandler;
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 3/10
TITLE : INTERRUPT HANDLER
BEGIN
inline( $50 { push ax }
/$53 { push bx }
/$51 { push cx }
/$52 { push dx } { Save all the }
/$57 { push di } { registers }
/$56 { push si }
/$06 { push es }
/$1E { push ds }
/$2E { cs: }
/$A1 /$A0 /$00{ mov ax, [00A0]} { Get the Current }
/$50 { push ax } { data segment }
/$1F { pop ds } ); { Restore the DS }
{ register }
tbyte := port[ comport ]; { Get the char in the port}
lbyte := port[ comport + linestat ]; { Get status of the port }
If ( head < buffsize ) then { Check bounds of the ring}
head := head + 1 { buffer, and if smaller }
else { then increment by one }
head := 0; { otherwise set to the }
{ first element }
intbuffer[ head ].o := tbyte; { Load the buffer w/ the }
{ character }
port[$20] := $20; { Enable all other }
{ interrupts except the }
{ calling INT ( 0C ) }
inline( $1F { pop ds }
/$07 { pop es }
/$5E { pop si }
/$5F { pop di }
/$5A { pop dx }
/$59 { pop cx } { Restore all registers }
/$5B { pop bx }
/$58 { pop ax }
/$5D { pop bp } { Reset the stack to its}
/$89 /$EC { mov sp,bp } { proper position }
/$5D { pop bp }
/$CF ); { iret } { Return }
END;
{---------------------------------------------------------------------
The procedure AskCom gets the comport to communicate through.
---------------------------------------------------------------------}
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 4/10
TITLE : INTERRUPT HANDLER
PROCEDURE AskCom( var comp : comtype );
VAR
ch : char;
BEGIN
write( 'What port is the modem in ( 1 or 2 ) : ' );
{ Write prompt }
Repeat
read( kbd,ch ); { Get the character }
Until ( ch in ['1','2'] ); { and check bounds }
If ( ch = '1' ) then
Begin
writeln( 'COM1:' ); { Set to COM1 }
comp := com1;
End
else
Begin
writeln( 'COM2:' );
comp := com2; { Set to COM2 }
End;
END;
{--------------------------------------------------------------------
This procedure sets the baud rate of the comport to either 300, 1200, 4800,
or 9600 baud. The Divisor latches are set according to the table in the
IBM hardware technical reference manual (p.1-238 ).
--------------------------------------------------------------------}
PROCEDURE SetRate(r:ratetype);
VAR
tlcr, { Line control register }
tdlmsb, { Divisor latch MSB }
tdllsb : byte; { Divisor latch LSB }
BEGIN
tdlmsb:=0; { Set DL MSB to 0 for 1200, }
{ 4800 and 9600 baud }
case r of { Use case to check baud rate }
rate300 : begin { Check for 300 baud }
tdlmsb:=1; { Set DL MSB to 01 }
tdllsb:=$80; { Set DL LSB to 80 }
end; { for a total of 0180 }
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 5/10
TITLE : INTERRUPT HANDLER
rate1200 : tdllsb:=$60; { 1200 set LSB to 60 }
rate4800 : tdllsb:=$18; { 4800 set LSB to 18 }
rate9600 : tdllsb:=$0c; { 0C for 9600 baud }
end;
tlcr:=port[comport+linectrl]; { Get the Line control }
{ register }
port[comport+linectrl]:=tlcr or $80; { Set Divisor Latch }
{ Access Bit in order to }
port[comport]:=tdllsb; { access divisor latches,}
{ then store the values }
port[comport+1]:=tdlmsb; { for the desired baud }
{ rate }
port[comport+linectrl]:=tlcr and $7f;{ then clear the DLAB }
{ in order to access to }
{ the receiver buffer }
END;
{--------------------------------------------------------------------
WhatRate is the input procedure that uses SetRate to set the correct
baud rate.
--------------------------------------------------------------------}
PROCEDURE WhatRate;
BEGIN
writeln; { Display prompt }
write('what baud rate ([3]00,[1]200,[4]800,[9]600) ');
read(kbd,kch); { Read in the baud rate }
-
case kch of
'3':SetRate(rate300); { Set the corresponding rate }
'1':SetRate(rate1200); { . }
'4':SetRate(rate4800); { . }
'9':SetRate(rate9600); { . }
end;
writeln(kch);
END;
{--------------------------------------------------------------------
The procedure IntOn sets up the interrupt handler vectors, and
communication protocol.
--------------------------------------------------------------------}
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 6/10
TITLE : INTERRUPT HANDLER
PROCEDURE IntOn(com:comtype);
CONST
bits5=0;
bits6=1;
bits7=2;
bits8=3;
stopbit1=0; { These are constants used }
stopbit2=4; { to define parity, stop }
noparity=0; { bits, data bits, etc. }
parity=8;
evenparity=16;
dtrtrue=1;
rtstrue=2;
bit3true=8;
VAR
tbyte : byte; { Temporary byte buffer }
i : integer; { counter }
BEGIN
head:=0; { Initialize the ring }
tail:=0; { buffer indexes }
case com of
com1:comport:=com1base; { Set the com port to }
{ talk to }
com2:comport:=com2base;
end;
tbyte := port[ comport ]; { Read the ports to clear }
tbyte := port[ comport + linestat ];{ any error conditions }
WhatRate; { Get the baud rate }
port[ comport + linectrl ] := bits7 + stopbit1 + noparity;
{ Set the protocall }
port[ comport + modemctrl ] := dtrtrue + rtstrue + bit3true;
port[ comport + intenreg ] := 1; { Enable com port }
tbyte := port[$21]; { interrupts }
with registers do
begin
ax:=$2500; { Load the function number }
{ for redefining an }
{ interrupt }
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 7/10
TITLE : INTERRUPT HANDLER
ds:=cseg; { Get and set the segment }
dx:=ofs(IntHandler); { and offset of the handler}
end;
case com of
com1: begin
oldvecoff:=memw[0000:irq4]; { Save the segment and }
oldvecseg:=memw[0000:irq4+2]; { offset of the DOS }
{ interrupt handler }
registers.ax:=registers.ax+$0c;
{ Use the COM1: interrupt }
intr($21,registers); { Call DOS to reset }
port[$21]:=tbyte and $ef; { INT 0C }
end;
com2: begin
oldvecoff:=memw[0000:irq3]; { Same as above }
oldvecseg:=memw[0000:irq3+2]; { Same as above }
registers.ax:=registers.ax+$0b;
{ Use the COM2: interrupt }
intr($21,registers); { Call DOS }
port[$21]:=tbyte and $f7; { }
end;
end;
inline($fb); { Enable interrupts }
END;
{---------------------------------------------------------------------
This procedure restores the original system values to what they were before
the interrupt handler was set into action.
---------------------------------------------------------------------}
PROCEDURE IntOff;
VAR
tbyte:byte;
BEGIN
inline($FA); { CLI } { Disable interrupts }
tbyte:=port[$21]; { }
port[comport+intenreg]:=0; { Disable COM interrupts }
If comport=$3f8 then { If using COM1: then }
begin
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 8/10
TITLE : INTERRUPT HANDLER
port[$21]:=tbyte or $10; { }
memw[0000:irq4]:=oldvecoff; { Restore the DOS }
memw[0000:irq4+2]:=oldvecseg; { interrupt handler }
end
else
begin
memw[0000:irq3]:=oldvecoff; { Restore the DOS }
memw[0000:irq3+2]:=oldvecseg; { interrupt handler }
port[$21]:=tbyte or $08; { }
end;e
END;
{------------------------------------------------------------------
If the ring buffer indexes are not equal then ReadCom returns the char from
either the COM1: or COM2: port. The character is read from the ring buffer
and is stored in the FUNCTION result.
-------------------------------------------------------------------}
FUNCTION ReadCom : char;
BEGIN
If ( head <> tail ) then { Check for ring buffer }
begin { character }
If ( tail < buffsize ) then { Check the limits of }
tail := tail + 1 { the ring and set tail }
else { accordingly }
tail := 0;
ReadCom := intbuffer[tail].c; { Get the character }
end;
END;
{------------------------------------------------------------------
This procedure outputs directly to the communications port the byte
equivilent of the character to be sent.
------------------------------------------------------------------}
PROCEDURE WriteCom( ch : char );
VAR
tbyte:byte;
BEGIN
tbyte:=ord(ch); { Change to byte format }
port[comport]:=tbyte; { Output the character }
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 9/10
TITLE : INTERRUPT HANDLER
END;
{------------------------------------------------------------------
When the interrupt routine is called because of a com port interrupt the
head index is incremented by one, but does not increment the tail index.
This causes the two indexes to be unequal, and ModemInput to become true.
------------------------------------------------------------------}
FUNCTION ModemInput:boolean;
begin
ModemInput:=(head<>tail);
end;
BEGIN
segment := dseg; { segment is an absolute variable used }
{ by the interrupt routine to restore }
{ the DS register to point to the DSEG }
AskCom( comp ); { Get the com port to use }
IntOn( comp ); { Set up the interrupt routine }
ch:=' '; { Initialize ch for the loop }
Repeat
If keypressed then { If a key is pressed on the keyboard }
begin
read(kbd,kch); { then the program reads it in and }
kch := Upcase(kch);
write( kch );
If ( kch = chr(13)) then writeln;
{ checks if the program should be ended }
WriteCom(kch); { Write the character to the com port }
end;
If ModemInput then { If something was placed in the ring }
begin { buffer then }
write('[');
ch:=ReadCom; { it is read in and printed to the }
write(ch); { screen }
If ch=chr(13) then writeln;
write(']');
end;
Until kch=chr(27); { This loops ends when <esc> is hit }
IntOff; { Restore the environment }
END. { Main program }
PRODUCT : TURBO PASCAL NUMBER : 152
VERSION : All
OS : PC-DOS, MS-DOS
DATE : August 1, 1986 PAGE : 10/10
TITLE : INTERRUPT HANDLER
DISCLAIMER: You have the right to use this technical information subject to
the terms of the No-Nonsense License Statement that you received with the
Borland product to which this information pertains.